package view.commands;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import view.SLogoView;
import view.components.ComponentsFactory;
import view.components.ErrorCatcher;

import model.turtle.Position;
import model.turtle.Turtle;

/**
 * Update coordinates due to list of turtles from model
 * @author Yin
 *
 */
public class Drawer implements Command<List<Turtle>>{
	
	private List<Turtle> myTurtles;
	private boolean myPenDown;
	private boolean myTurtleShown;
	private double myDegree;
	private BufferedImage myBufferedImage;
	private Position myPosition;
    private Position mySwap;
    private List<List<Integer>> myAllX;
    private List<List<Integer>> myAllY;
	
	private static final String TURTLE_READING_ERROR = "TurtleError";
    private static final String TURTLE_CANVAS_SIZE = "TurtleCanvasSize";
	
	public Drawer(BufferedImage image)
	{
		myBufferedImage = image;
		reset();
	}
	
	/**
	 * Initialize
	 */
	protected void reset()
	{
		myTurtles = new ArrayList<Turtle>();
		myPenDown = true;
		myTurtleShown = true;
		myDegree = 0;
		
		myAllX = new ArrayList<List<Integer>>();
	    myAllY = new ArrayList<List<Integer>>();
	    
	    myPosition = new Position(0, 0, 0);
	    myPosition.setX((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(0)/2-myBufferedImage.getWidth()/2);
	    myPosition.setY((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(1)/2-myBufferedImage.getHeight()/2);
	    myPosition.setDirection(0);
	    mySwap = myPosition;

	    myAllX.add(new ArrayList<Integer>());
	    myAllX.get(0).add(myPosition.getX() + myBufferedImage.getWidth() / 2);
	    myAllY.add(new ArrayList<Integer>());
	    myAllY.get(0).add(myPosition.getY() + myBufferedImage.getHeight() / 2);
	}

	/**
	 * Update coordinates
	 * Return 1 if update succeeds, and return 0 if not.
	 */
	@Override
	public Integer execute(List<Turtle> turtles) {
		if (turtles != null)
            this.myTurtles = turtles;
        else
        {
        	new ErrorCatcher(ComponentsFactory.getComponentsMap().get(TURTLE_READING_ERROR));
        	return 0;
        }
		
		for (Turtle turtle: myTurtles)
		{
			myPenDown = !(turtle.isPenDown()==0);
            myTurtleShown = !(turtle.isShow()==0);
            
            List<Position> trail = turtle.getTrail();
    		if(trail.size()==0 || trail==null)
            {                               
                    // If no trail exists, paint the turtle in its current position
                    continue;
            }
    		
    		if (trail.size()==1)
            {
            	reset();
            	continue;
            }
    		
    		// Initialize coordinates of starting point
    		List<Integer> xroute = new ArrayList<Integer>();
            List<Integer> yroute = new ArrayList<Integer>();
            updateCoordinates(xroute, yroute, turtle.getX(), turtle.getY());
            
            myDegree = 0;
            while(trail.size()!=0)
            {
                    mySwap = trail.remove(0);
                    
                    // Update turtle trail
                    if (myPenDown) // Draw lines
                            updateCoordinates(xroute, yroute, mySwap.getX(), mySwap.getY());
                    else  // Hide lines
                            updateCoordinates(xroute, yroute, turtle.getX(),turtle.getY());
                    
                    // Update turtle direction
                    myDegree += (double) myPosition.getDirection() - mySwap.getDirection();
                    
                    // Update turtle position
                    myPosition.setX((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(0)/2 + mySwap.getX() - myBufferedImage.getWidth()/2);
                    myPosition.setY((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(1)/2 - mySwap.getY() - myBufferedImage.getHeight()/2);
                    myPosition.setDirection(mySwap.getDirection());
                    
            }
            
            trail.add(mySwap);
            
            myAllX.add(xroute);
            myAllY.add(yroute);
            
		}
		
		return 1;
	}
	
	/**
	 * A helper method that can convert coordinates to canvas system
	 * @param xlist and @param ylist are lists to be updated
	 * @param deltax
	 * @param deltay
	 */
	protected void updateCoordinates(List<Integer> xlist, List<Integer> ylist, int deltax, int deltay)
    {
		xlist.add((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(0)/2 + deltax);
        ylist.add((int) SLogoView.getSize(TURTLE_CANVAS_SIZE).get(1)/2 - deltay);
    }
	
	/**
	 * 
	 * @return all x coordinates
	 */
	public List<List<Integer>> getXs()
	{
		return myAllX;
	}
	
	/**
	 * 
	 * @return all y coordinates
	 */
	public List<List<Integer>> getYs()
	{
		return myAllY;
	}
	
	/**
	 * 
	 * @return degree for rotation
	 */
	public double getDegree()
	{
		return myDegree;
	}
	
	/**
	 * 
	 * @return turtle's final position
	 */
	public Position getPosition()
	{
		return myPosition;
	}
	
	/**
	 * 
	 * @return a status indicating whether a turtle is shown on screen
	 */
	public boolean turtleIsShown()
	{
		return myTurtleShown;
	}

}
